/*********************************
 * jsmud: JavaScript MUD Kernel  *
 *          Mojodo, Inc.         *
 *        Sean Middleditch       *
 * Copyright (C) 2005,2007,2008  *
 *      All rights reserved.     *
 *   See COPYING for licensing.  *
 *********************************/

/* ==== COMPILE-TIME CONFIGURATION - ADVANCED ==== */

#define TELNET_COMMAND_SIZE 1024
#define TELNET_SUB_REQUEST_SIZE (1024 * 8)
#define TELNET_ZMP_MAX_ARGS 32

/* ==== ENUMERATIONS AND FLAGS ==== */

enum TelnetMode {
	TM_TEXT,
	TM_IAC,
	TM_WILL,
	TM_WONT,
	TM_DO,
	TM_DONT,
	TM_SUB,
	TM_SUB_IAC
};

enum InputMode {
	IN_LINE,
	IN_CHARACTER,
	IN_NULL
};

#define TF_WANT_ECHO 	(1 << 0)
#define TF_DO_ECHO		(1 << 1)
#define TF_HAVE_ZMP 	(1 << 2)

#define TELOPT_ZMP 93
#define TELOPT_MCCP 86

/* ==== TYPE DEFINITIONS ==== */

typedef unsigned char byte;

/* Custom settings list, which scripts can query */
struct Setting {
	char* name;
	char* value;
	struct Setting* next;
};
typedef struct Setting Setting;

/* A socket that we are listening on, and callback to invoke on connection */
struct Listen {
	jsval callback;
	char* interface;
	struct Listen* next;
	int sock;
	short port;
};
typedef struct Listen Listen;

/* A connected telnet client */
struct Client {
	jsval object;
	char* cmd_buf;
	char* sub_buf;
	struct z_stream_s* zlib;
	struct Client* next;
	struct Client* prev;
	int sock;
	int cmd_len;
	int sub_len;
	int flags;
	enum TelnetMode tmode;
	enum InputMode imode;
};
typedef struct Client Client;

/* A timer */
struct Timer {
	jsval callback;
	struct Timer* next;
	double time_original;
	double time_remaining;
	char gametime;
};
typedef struct Timer Timer;

/* A ZMP handler */
struct ZMPHandler {
	jsval callback;
	struct ZMPHandler* next;
	char* name;
};
typedef struct ZMPHandler ZMPHandler;

/* ==== GLOBALS ==== */

/* -- JavaScript -- */
extern JSRuntime* js_runtime;
extern JSContext* js_context;
extern JSObject* js_global;
extern JSClass js_resultset_class;
extern JSObject* js_resultset_prototype;
extern JSClass js_connection_class;
extern JSObject* js_connection_prototype;

extern const char stdlib_js[];
extern const unsigned int stdlib_js_len;

/* -- Database -- */
extern sqlite3* db_context;

/* -- Runtime options -- */
extern const char* opt_log_path;
extern const char* opt_data_path;
extern Setting* opt_custom;

/* -- Logging -- */
extern FILE* log_file;
extern int log_quiet;

/* -- Network -- */
extern Listen* listen_list;
extern Client* client_list;
extern Client* client_next;

/* -- Timers -- */
extern Timer* timer_list;
extern double timer_game_scale;

/* -- ZMP Handlers -- */
extern ZMPHandler* zmp_handler_list;

/* -- Runtime exit flag -- */
extern volatile int exit_flag;

/* ==== FUNCTION DECLARATIONS ==== */

/* -- Logging -- */
extern void log_time (FILE* file);
extern void log_msg (const char* format, ...);

/* -- Error handling -- */
extern void log_error (const char* format, ...);
extern void javascript_error (JSContext* context, const char* msg, JSErrorReport* error);

/* -- Networking -- */
extern Listen* listen_new (const char* interface, short port, jsval* accept);
extern Client* client_new (int sock);
extern void client_disconnect (Client* client);
extern void client_send_raw (Client* client, const char* bytes, int length);
extern void client_send (Client* client, const char* bytes, int length);
extern void client_send_text (Client* client, const char* bytes, int length);
extern void client_send_iac (Client* client, int cmd, int opt);
extern void client_send_zmp (Client* client, const char* cmd, int argc, const char** argv);
extern void client_flush (void);
extern void listen_accept (fd_set* set);
extern void client_update (fd_set* set);
extern void client_process (Client* client, const char* bytes, int length);
extern void client_handle_telnet_subreq (Client* client);
extern void client_handle_zmp (Client* client, const char* bytes, int length);
extern int client_append_text (Client* client, char c);
extern void build_fd_set (fd_set* set, int* max);
extern void listen_free_all (void);
extern void client_free_all (void);

/* -- Timers -- */
extern Timer* timer_new (double time, char gametime, jsval* callback);
extern double timer_next (void);
extern void timer_update (double elapsed);
extern void timer_free_all (void);

/* -- ZMP Handlers -- */
extern ZMPHandler* zmp_register (const char* name, jsval* callback);
extern int zmp_call (Client* client, int argc, const char** argv);
extern int zmp_has (const char* name);
extern void zmp_free_all (void);

/* -- Database -- */
extern sqlite3_stmt* db_prepare (const char* sql, uintN argc, jsval* argv);
extern JSBool db_get_result (sqlite3_stmt* stmt, jsval* result);
extern JSBool db_get_result_array (sqlite3_stmt* stmt, jsval* result);

/* -- Argument parsing -- */
extern int parse_argv (int argc, char** argv);

/* -- Signal processing -- */
extern void signal_exit_handler (int signal);

/* -- Utility functions -- */
extern const char* makepath (const char* path);

/* -- JavaScript -- */
extern int js_init (void);
extern int js_main (void);
extern JSBool js_call_method (JSObject* object, const char* name, int argc, jsval* argv);
extern JSObject* jsval_to_object (jsval val);
extern void js_raise (JSContext* cx, const char* fmt, ...);

extern int init_filelib (void);
extern int init_netlib (void);
extern int init_timerlib (void);
extern int init_dblib (void);
extern int init_stdlib (void);

#define JSAPI(name) static JSBool name (JSContext* cx, JSObject* self, uintN argc, jsval* argv, jsval* rval)
